package org.ithasu.tools.net.http;

import java.net.URL;
import java.net.URLEncoder;

import org.ithasu.tools.Console;
import org.ithasu.tools.StringTools;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.select.Elements;

public abstract class SearchEngine implements Runnable {

	private final int SEARCH_ENGINE_TIMEOUT_MS = 30000;
	private final String query;
	private Document result;

	private Thread fetchThread = null;

	public SearchEngine(String query) {
		this.query = query;
		reprocess(false);
	}

	// --- Query ----------------------------------------

	public String getQuery() {
		return query;
	}

	public String getEncodedQuery() {
		try {
			return URLEncoder.encode(query, StringTools.UTF8);
		} catch (Exception e) {
			Console.error(e);
			return StringTools.EMPTY_STRING;
		}
	}

	/**
	 * Should return url to fetch data from. Paged at this url will be fetched
	 * and stored to allow retrieving information.
	 */
	protected abstract String getQueryURL();

	// --- Fetch data ----------------------------------------

	/** @return true if data were fetched. */
	public boolean done() {
		return fetchThread != null && !fetchThread.isAlive();
	}

	public boolean processing() {
		return fetchThread != null && fetchThread.isAlive();
	}

	/** @return page fetched. Blocking method. */
	public Document getDocument() {
		try {
			if (fetchThread == null || fetchThread.isInterrupted()) {
				return null;
			}
			if (fetchThread.isAlive()) {
				fetchThread.join();
			}
			return result;
		} catch (InterruptedException e) {
			Console.error(e);
			return null;
		}
	}

	/** Automatically called by constructor. Non blocking. */
	public void reprocess() {
		reprocess(false);
	}

	/** Automatically called by constructor. Non blocking. */
	public void reprocess(boolean blocking) {
		if (processing()) {
			// Already launched ... be patient
		} else {
			fetchThread = new Thread(this);
			fetchThread.start();
		}

		if (blocking) {
			getDocument();
		}
	}

	// --- Processing ----------------------------------------

	@Override
	public void run() {
		result = null;
		try {
			result = Jsoup.parse(new URL(getQueryURL()), SEARCH_ENGINE_TIMEOUT_MS);
		} catch (Exception e) {
			Console.error(e);
			result = null;
		}
	}

	// --- Results ----------------------------------------

	public Elements select(String cssQuery) {
		Document doc = getDocument();
		if (doc == null) {
			return null;
		} else {
			return doc.select(cssQuery);
		}
	}

}